package common

import (
	"bytes"
	"fmt"
	"pan/command"
	"pan/common/conf"
	"pan/common/exception"
	"pan/common/log"
	"runtime"
)

var GlobalManager *Manager

func init() {
	manager := &Manager{}
	manager.Init()
	GlobalManager = manager
}

type BuildArgs struct {
	LogLevel string
}

type Manager struct {
	isInitialized bool

	registry *command.Registry
}

func (m *Manager) Init() {
	if m.isInitialized {
		return
	}

	conf.GlobalConfig = conf.NewConfigure()
	_ = conf.GlobalConfig.Load("")

	conf.GlobalToken = conf.NewToken()
	conf.GlobalToken.Load()

	conf.GlobalRsaPubKey = conf.NewRsaPublicKey()
	conf.GlobalRsaPubKey.Load()

	if conf.GlobalConfig.LogLevel != "" {
		log.SetLevelName(conf.GlobalConfig.LogLevel)
	}
	m.registerCommand()

	m.isInitialized = true
}

func (m *Manager) Start(args BuildArgs) {
	if !m.isInitialized {
		log.Error("Manager not initialized")
		return
	}
	m.setup(&args)
	defer panicHandle()
	m.registry.Run()
}

func (m *Manager) setup(args *BuildArgs) {
	log.SetLevelName(args.LogLevel)
}

func (m *Manager) registerCommand() {
	m.registry = command.NewRegistry()
	m.registry.Register("login", command.NewLoginCommand())
	m.registry.Register("refresh", command.NewRefreshTokenCommand())
	m.registry.Register("doc", command.NewDocsCommand())
	m.registry.Register("dir", command.NewDirCommand())
	m.registry.Register("download", command.NewDownloadCommand())
	m.registry.Register("fdownload", command.NewFastDownloadCommand())
	m.registry.Register("upload", command.NewUploadCommand())
}

func panicHandle() {
	if err := recover(); err != nil {
		if e, ok := err.(*exception.ExpectError); ok {
			log.Error(e.Error())
		} else {
			msg := getStackTrace(err)
			log.Error(msg)
		}
	}
}

func getStackTrace(err interface{}) string {
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "%v\n", err)
	for i := 1; ; i++ {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
	}
	return buf.String()
}
